package zdream.pmfield.stage.buff.ailment;

import java.util.Objects;

import zdream.pmfield.data.foe.BStat;
import zdream.pmfield.data.foe.MoveAdditionalEffects;
import zdream.pmfield.data.foe.MoveCheckPair;
import zdream.pmfield.data.foe.MoveTarget;
import zdream.pmfield.data.foe.MoveTargetType;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.data.foe.MoveType;
import zdream.pmfield.data.foe.Type;
import zdream.pmfield.data.foe.VStat;
import zdream.pmfield.stage.action.AttackAction;
import zdream.pmfield.stage.action.BuffAction;
import zdream.pmfield.stage.buff.foe.FoeStageBuff;
import zdream.pmfield.stage.director.AttackContext;
import zdream.pmfield.stage.director.HookType;
import zdream.pmfield.stage.director.Hooks;
import zdream.pmfield.stage.message.FoeReceiveDamageMessage;
import zdream.pmfield.stage.object.FoeActor;
import zdream.pmfield.stage.object.StageMove;

/**
 * <p>碎片效果状态
 * <p>处于碎片状态后, 每次行动结束受到固定威力无属性
 * ({@link zdream.pmfield.data.foe.Type#OTHER}) 伤害.
 * <p>碎片状态会记录造成状态的招式和招式使用者, 每次触发时,
 * 重新计算防御方修正.
 * </p>
 *
 * <p>
 * 碎片效果能自然恢复, 3 次触发之后投骰子判断是否恢复 (不是按回合数).
 * 主要通过 {@link zdream.pmfield.data.foe.VStat#LUCK} 来决定是否恢复.
 * </p>
 *
 * @author Zdream
 * @date 2023-12-14
 * @since 0.0.1
 */
public class SplintersBuff extends FoeStageBuff {
	public static final String CATEGORY = MoveAdditionalEffects.E_SPLINTERS;
	public final BuffSpan span;
	private StageMove pureMove;
	private int lastAttack;

	public SplintersBuff(FoeActor foe) {
		super(foe);
		span = new CountBuffSpan()
				.withMinCount(3);
	}

	@Override
	public String getCategory() {
		return CATEGORY;
	}

	@Override
	public void init() {
		preventSameBuffBeforeFoeReceiveBuff();
		createPureStageMove();
		onHook(HookType.BEFORE_FOE_TURN_START)
				.handle(this::checkCuredAndTakeDamage)
				.buildAndSave();
	}

	private void createPureStageMove() {
		final AttackContext currentAttack = target.stage.director.getCurrentAttackContext();
		StageMove rawMove = Objects.requireNonNull(currentAttack).currentMove;

		MoveTemplate template = new MoveTemplate(0);
		template.name = CATEGORY;
		template.level = 1;
		template.types = new Type.TypeWithWeight[] { Type.OTHER.withFullWeight };
		template.attackerUsing = rawMove.attackerUsing;
		if (template.attackerUsing != MoveType.PHYSICAL) {
			template.attackerUsing = MoveType.SPECIAL;
		}
		template.defenseUsing = template.attackerUsing;
		template.target = new MoveTarget(MoveTargetType.ENEMY);
		template.vStats = new VStat[0];

		MoveCheckPair pair = new MoveCheckPair();
		pair.level = 0;
		pair.result = MoveCheckPair.RESULT_MAJOR_SUCCESS;
		pair.power = Math.max(rawMove.findFullLevelPair().power / 2, 10);
		template.pairs = new MoveCheckPair[] {pair};

		this.pureMove = new StageMove(target, template);
		this.lastAttack = currentAttack.attacker.getBStat(
				template.attackerUsing == MoveType.PHYSICAL ? BStat.AT : BStat.SA);
	}

	public void checkCuredAndTakeDamage(Hooks.HookContext rawContext) {
		Hooks.BeforeTurnHookContext context = rawContext.as();
		if (context.foe != target) {
			return;
		}

		boolean cured = span.checkIsNeedCured();
		if (cured) {
			return;
		}

		// 计算伤害
		AttackAction action = new AttackAction(target);
		action.move = pureMove;
		action.targetFoe = target;

		final AttackContext attackContext = AttackContext.createDryRun(action, pureMove.findFullLevelPair());
		attackContext.attack = lastAttack;
		attackContext.skipCalcAttack = true;

		target.stage.moveChecker.evaluateAttack(attackContext);
		int damage = attackContext.items.get(0).damage;
		putBuffActionNow(buildTask(damage));
	}

	private static String buildTask(int damage) {
		return String.format("damage=%d", damage);
	}

	private static int parseTask(String task) {
		return Integer.parseInt(task.split("=")[1]);
	}

	@Override
	public void doTask(BuffAction action) {
		int damage = parseTask(action.task);

		final FoeReceiveDamageMessage damageMessage = new FoeReceiveDamageMessage(target)
				.withDamage(damage)
				.withTitle(CATEGORY)
				.withHpFrom(target);

		target.receiveDamage(damage);
		pushMessage(damageMessage.withHpTo(target));
	}

	@Override
	public String toString() {
		return "碎片";
	}
}
